/* 字符串的操作：统计某篇英文小说中某些单词的出现次数和位置。英文小说存于一个文本文件中。待统计的词
汇集合要一次输入完毕，即统计工作必须在程序的一次运行之后就全部完成。程序的输出结果是
每个词的出现次数和出现位置所在行的行号，将输出结果保存在一个文本文件中。*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define NUM 33

const char *keywords[NUM] = {
    "auto", "break", "case", "char", "const", "continue", "default", "do",
    "double", "else", "enum", "extern", "float", "for", "goto", "if",
    "int", "long", "register", "restrict", "return", "short", "signed",
    "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned",
    "void", "volatile", "while"
};

struct LineNode {
    int lineNumber; 
    struct LineNode *next; 
};

struct Keyword {
    char name[15];
    struct LineNode *lineList; 
};

struct Keyword keywordList[NUM];

void analyse_line(char *line, int lineNumber) {
    char word[100];
    int i = 0;

    while (line[i] != '\n' && line[i] != '\0') {
        int length = 0; // 为每个新单词重置长度
        // 提取下一个单词
        while (line[i] >= 'a' && line[i] <= 'z') {
            word[length++] = line[i++];
        }
        word[length] = '\0'; // 以空字符结束字符串
        i++;
        // 检查提取的单词是否为关键词
        for (int j = 0; j < NUM; j++) {
            if (strcmp(word, keywords[j]) == 0) {
                struct LineNode *lineNode = (struct LineNode *) malloc(sizeof(struct LineNode));
                lineNode->lineNumber = lineNumber; // 存储行号
                lineNode->next = NULL;

                // 将节点插入到链表中
                struct LineNode *currentNode = keywordList[j].lineList;
                if (currentNode == NULL) {
                    keywordList[j].lineList = lineNode; // 如果没有节点，添加新节点
                } else {
                    while (currentNode->next != NULL) {
                        currentNode = currentNode->next; // 遍历到末尾
                    }
                    currentNode->next = lineNode; // 在末尾添加新节点
                }
            }
        }
    }
}

int main() {
    // 初始化 keywordList 数组
    for (int i = 0; i < NUM; i++) {
        strcpy(keywordList[i].name, keywords[i]);
        keywordList[i].lineList = NULL;
    }

    // 打开文件进行读取
    FILE *file = fopen("4_1.c", "r");
    if (file == NULL) {
        perror("打开文件时出错");
        return 0;
    }
    char line[100];
    int lineNumber = 0;
    while (fgets(line, sizeof(line), file) != NULL) {
        lineNumber++;
        analyse_line(line, lineNumber); // 分析每一行的关键词
    }

    fclose(file); // 读取完文件后关闭
    FILE *outputFile = fopen("answer", "w");

    // 打印格式化结果
    fprintf(outputFile, "关键词分析结果:\n");
    fprintf(outputFile, "------------------------------------------------------------------------------------------------------------------------------------------------------\n");

    for (int i = 0; i < NUM; i++) {
        int occurrenceCount = 0;
        // 打印关键词的名称，右对齐
        fprintf(outputFile, "%-12s: ", keywordList[i].name); // 设置宽度为12，左对齐
        struct LineNode *currentNode = keywordList[i].lineList;
        
        if (currentNode == NULL) {
            fprintf(outputFile, "没有出现\n");
        } else {
            // 输出每个关键词出现的行号
            while (currentNode != NULL) {
                occurrenceCount++;
                fprintf(outputFile, "第%-3d行 ", currentNode->lineNumber);
                currentNode = currentNode->next; // 移动到下一个节点
            }
            fprintf(outputFile, "总计 %d 个\n", occurrenceCount);
        }
    }

    fprintf(outputFile, "---------------------------------------------------------------------------------------------------------------------------------------------------------------------\n");
    fclose(outputFile); // 写入完毕后关闭文件

    return 0;
}
